package ltd.smallwang;

import java.util.LinkedList;
import java.util.List;

/**
 * @author justd
 * @date 2024-11-23 09:10
 */
public class Leetcode0054 {

  public List<Integer> spiralOrder(int[][] matrix) {
    boolean[][] visited = new boolean[matrix.length][matrix[0].length];
    int length = matrix.length * matrix[0].length;
    int currX = -1;
    int currY = 0;
    Direction direction = Direction.RIGHT;
    List<Integer> result = new LinkedList<>();
    for (int i = 0; i < length; i++) {
      direction = nextDirection(direction, currX, currY, visited);
      int[] nextPoint = nextPoint(currX, currY, direction);
      currX = nextPoint[0];
      currY = nextPoint[1];
      visited[currY][currX] = true;
      result.add(matrix[currY][currX]);
    }
    return result;
  }

  private int[] nextPoint(int currX, int currY, Direction direction) {
    switch (direction) {
      case RIGHT:
        return new int[] { currX + 1, currY };
      case DOWN:
        return new int[] { currX, currY + 1 };
      case LEFT:
        return new int[] { currX - 1, currY };
      case UP:
      default:
        return new int[] { currX, currY - 1 };
    }
  }

  private Direction nextDirection(Direction direction, int currX, int currY, boolean[][] visited) {
    switch (direction) {
      case RIGHT:
        if (currX + 1 >= visited[0].length) {
          return Direction.DOWN;
        }
        if (visited[currY][currX + 1]) {
          return Direction.DOWN;
        }
        return Direction.RIGHT;
      case DOWN:
        if (currY + 1 >= visited.length) {
          return Direction.LEFT;
        }
        if (visited[currY + 1][currX]) {
          return Direction.LEFT;
        }
        return Direction.DOWN;
      case LEFT:
        if (currX - 1 < 0) {
          return Direction.UP;
        }
        if (visited[currY][currX - 1]) {
          return Direction.UP;
        }
        return Direction.LEFT;
      case UP:
      default:
        if (currY - 1 < 0) {
          return Direction.RIGHT;
        }
        if (visited[currY - 1][currX]) {
          return Direction.RIGHT;
        }
        return Direction.UP;
    }
  }

  private enum Direction {
    /**
     * 定义了四个常量，分别表示右、下、左、上的方向
     * 这些常量用于在代码中表示不同的方向，使得代码更易于理解和维护
     */
    RIGHT, DOWN, LEFT, UP
  }
}
